/**
 * Copyright 2013 ABSir's Studio
 * 
 * All right reserved
 *
 * Create on 2013-6-19 上午9:24:49
 */
package com.absir.android.inject;

import java.lang.reflect.Field;

import android.graphics.drawable.Drawable;

import com.absir.android.app.ApplicationBean;
import com.absir.android.inject.annotation.InjectResouce;
import com.absir.android.view.InjectViewUtils;
import com.absir.bean.basis.BeanFactory;
import com.absir.bean.inject.IFieldSupport;
import com.absir.bean.inject.InjectInvoker;
import com.absir.bean.inject.value.Bean;
import com.absir.bean.inject.value.InjectType;
import com.absir.core.kernel.KernelClass;
import com.absir.core.kernel.KernelLang.CauseRuntimeException;

/**
 * @author absir
 * 
 */
@Bean
public class InjectResouceSupply implements IFieldSupport {

	/**
	 * @author absir
	 * 
	 * @param <T>
	 */
	private static abstract class InjectResouceType<T> {

		/** type */
		private Class<?> type;

		/**
		 * 
		 */
		public InjectResouceType() {
			type = KernelClass.componentClass(this.getClass());
		}

		/**
		 * @param id
		 * @param name
		 * @return
		 */
		public T getResouce(int id, String name) {
			id = InjectViewUtils.getResouceId(id, type.getSimpleName(), name);
			if (id == InjectViewUtils.ID_ZERO) {
				return null;
			}

			return getResouce(id);
		}

		/**
		 * @param id
		 * @return
		 */
		protected abstract T getResouce(int id);
	}

	/** injectResouceTypes */
	private static InjectResouceType<?>[] injectResouceTypes = new InjectResouceType<?>[] {

	new InjectResouceType<String>() {

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * com.absir.android.inject.InjectResouceSupply.InjectResouceType#getResouce
		 * (int)
		 */
		@Override
		protected String getResouce(int id) {
			// TODO Auto-generated method stub
			return ApplicationBean.getApplication().getResources().getString(id);
		}
	},

	new InjectResouceType<String[]>() {

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * com.absir.android.inject.InjectResouceSupply.InjectResouceType#getResouce
		 * (int)
		 */
		@Override
		protected String[] getResouce(int id) {
			// TODO Auto-generated method stub
			return ApplicationBean.getApplication().getResources().getStringArray(id);
		}
	},

	new InjectResouceType<Drawable>() {

		/*
		 * (non-Javadoc)
		 * 
		 * @see
		 * com.absir.android.inject.InjectResouceSupply.InjectResouceType#getResouce
		 * (int)
		 */
		@Override
		protected Drawable getResouce(int id) {
			// TODO Auto-generated method stub
			return ApplicationBean.getApplication().getResources().getDrawable(id);
		}
	},

	};

	/**
	 * @author absir
	 * 
	 */
	private static class InjectResouceInvoker extends InjectInvoker {

		/** id */
		int id;

		/** field */
		Field field;

		/** injectResouceType */
		InjectResouceType<?> injectResouceType;

		/**
		 * @param required
		 */
		public InjectResouceInvoker(int id, Field field, InjectResouceType<?> inResouceType, boolean required) {
			// TODO Auto-generated constructor stub
			super(required ? InjectType.Required : InjectType.Selectable);
			this.id = id;
			this.field = field;
			this.injectResouceType = inResouceType;
		}

		@Override
		public boolean support(Class<?> beanType) {
			// TODO Auto-generated method stub
			return false;
		}

		/*
		 * (non-Javadoc)
		 * 
		 * @see com.absir.bean.inject.InjectInvoker#invoke(com.absir.bean.basis.
		 * BeanFactory, java.lang.Object)
		 */
		@Override
		public void invoke(BeanFactory beanFactory, Object beanObject) {
			// TODO Auto-generated method stub
			Object value = injectResouceType.getResouce(id, field.getName());
			if (value == null || !field.getType().isAssignableFrom(value.getClass())) {
				if (getInjectType() == InjectType.Required) {
					throw new RuntimeException("can not inject " + field.getDeclaringClass() + ".field " + field);
				}

				return;
			}

			try {
				field.set(beanObject, value);

			} catch (Exception e) {
				// TODO Auto-generated catch block
				throw new CauseRuntimeException(e);
			}
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.absir.bean.inject.value.IFieldSupport#getInjectInvoker(java.lang.
	 * reflect.Field)
	 */
	@Override
	public InjectInvoker getInjectInvoker(Field field) {
		// TODO Auto-generated method stub
		InjectResouce injectResouce = field.getAnnotation(InjectResouce.class);
		if (injectResouce != null) {
			Class<?> type = field.getType();
			for (InjectResouceType<?> injectResouceType : injectResouceTypes) {
				if (injectResouceType.type.isAssignableFrom(type)) {
					return new InjectResouceInvoker(injectResouce.value(), field, injectResouceType,
							injectResouce.required());
				}
			}
		}

		return null;
	}
}
